﻿using System.Data;
using System.Diagnostics;

namespace System
{
  [DebuggerStepThrough]
  public static class DataReaderExtensions
  {

    public static Boolean ColumnExists(this IDataReader dr, String columnName)
    {
      for (Int32 i = 0; i < dr.FieldCount; i++)
      {
        if (dr.GetName(i).Equals(columnName, StringComparison.OrdinalIgnoreCase))
        {
          return true;
        }
      }

      return false;
    }
    public static DataTable ToDataTable(this IDataReader dr)
    {
      var dt = new DataTable();
      for (int i = 0; i > dr.FieldCount; ++i)
      {
        dt.Columns.Add(new DataColumn {ColumnName = dr.GetName(i), DataType = dr.GetFieldType(i)});
      }

      while (dr.Read())
      {
        DataRow row = dt.NewRow();
        dr.GetValues(row.ItemArray);
        dt.Rows.Add(row);
      }

      return dt;
    }

    public static T Get<T>(this IDataReader reader, string field) {
        return reader.Get(field, default(T));
    }
    public static T Get<T>(this IDataReader reader, string field, T defaultValue) {
        var value = reader[field];
        if (value == DBNull.Value)
            return defaultValue;

        if (value is T)
            return (T)value;

        return value.ConvertTo(defaultValue);
    }
    public static byte[] GetBytes(this IDataReader reader, string field) {
        return (reader[field] as byte[]);
    }
    public static string GetString(this IDataReader reader, string field) {
        return reader.GetString(field, null);
    }
    public static string GetString(this IDataReader reader, string field, string defaultValue) {
        var value = reader[field];
        return (value is string ? (string)value : defaultValue);
    }
    public static Guid GetGuid(this IDataReader reader, string field) {
        var value = reader[field];
        return (value is Guid ? (Guid)value : Guid.Empty);
    }
    public static Guid? GetNullableGuid(this IDataReader reader, string field) {
        var value = reader[field];
        return (value is Guid ? (Guid?)value : null);
    }
    public static DateTime GetDateTime(this IDataReader reader, string field) {
        return reader.GetDateTime(field, DateTime.MinValue);
    }
    public static DateTime GetDateTime(this IDataReader reader, string field, DateTime defaultValue) {
        var value = reader[field];
        return (value is DateTime ? (DateTime)value : defaultValue);
    }
    public static DateTime? GetNullableDateTime(this IDataReader reader, string field) {
        var value = reader[field];
        return (value is DateTime ? (DateTime?)value : null);
    }
    public static DateTimeOffset GetDateTimeOffset(this IDataReader reader, string field) {
        return new DateTimeOffset(reader.GetDateTime(field), TimeSpan.Zero);
    }
    public static DateTimeOffset GetDateTimeOffset(this IDataReader reader, string field, DateTimeOffset defaultValue) {
        var dt = reader.GetDateTime(field);
        return (dt != DateTime.MinValue ? new DateTimeOffset(dt, TimeSpan.Zero) : defaultValue);
    }
    public static DateTimeOffset? GetNullableDateTimeOffset(this IDataReader reader, string field) {
        var dt = reader.GetNullableDateTime(field);
        return (dt != null ?  (DateTimeOffset?) new DateTimeOffset(dt.Value, TimeSpan.Zero) : null);
    }
    public static int GetInt32(this IDataReader reader, string field) {
        return reader.GetInt32(field, 0);
    }
    public static int GetInt32(this IDataReader reader, string field, int defaultValue) {
        var value = reader[field];
        return (value is int ? (int)value : defaultValue);
    }
    public static int? GetNullableInt32(this IDataReader reader, string field) {
        var value = reader[field];
        return (value is int ? (int?)value : null);
    }
    public static long GetInt64(this IDataReader reader, string field) {
        return reader.GetInt64(field, 0);
    }
    public static long GetInt64(this IDataReader reader, string field, int defaultValue) {
        var value = reader[field];
        return (value is long ? (long)value : defaultValue);
    }
    public static long? GetNullableInt64(this IDataReader reader, string field) {
        var value = reader[field];
        return (value is long ? (long?)value : null);
    }
    public static decimal GetDecimal(this IDataReader reader, string field) {
        return reader.GetDecimal(field, 0);
    }
    public static decimal GetDecimal(this IDataReader reader, string field, long defaultValue) {
        var value = reader[field];
        return (value is decimal ? (decimal)value : defaultValue);
    }
    public static decimal? GetNullableDecimal(this IDataReader reader, string field) {
        var value = reader[field];
        return (value is decimal ? (decimal?)value : null);
    }
    public static bool GetBoolean(this IDataReader reader, string field) {
        return reader.GetBoolean(field, false);
    }
    public static bool GetBoolean(this IDataReader reader, string field, bool defaultValue) {
        var value = reader[field];
        return (value is bool ? (bool)value : defaultValue);
    }
    public static bool? GetNullableBoolean(this IDataReader reader, string field) {
        var value = reader[field];
        return (value is bool ? (bool?)value : null);
    }
    public static Type GetType(this IDataReader reader, string field) {
        return reader.GetType(field, null);
    }
    public static Type GetType(this IDataReader reader, string field, Type defaultValue) {
        var classType = reader.GetString(field);
        if (classType.IsNotEmpty()) {
            var type = Type.GetType(classType);
            if (type != null)
                return type;
        }
        return defaultValue;
    }
    public static object GetTypeInstance(this IDataReader reader, string field) {
        return reader.GetTypeInstance(field, null);
    }
    public static object GetTypeInstance(this IDataReader reader, string field, Type defaultValue) {
        var type = reader.GetType(field, defaultValue);
        return (type != null ? Activator.CreateInstance(type) : null);
    }
    public static T GetTypeInstance<T>(this IDataReader reader, string field) where T : class {
        return (reader.GetTypeInstance(field, null) as T);
    }
    public static T GetTypeInstanceSafe<T>(this IDataReader reader, string field, Type type) where T : class {
        var instance = (reader.GetTypeInstance(field, null) as T);
        return (instance ?? Activator.CreateInstance(type) as T);
    }
    public static T GetTypeInstanceSafe<T>(this IDataReader reader, string field) where T : class, new() {
        var instance = (reader.GetTypeInstance(field, null) as T);
        return (instance ?? new T());
    }
    public static bool IsDBNull(this IDataReader reader, string field) {
        var value = reader[field];
        return (value == DBNull.Value);
    }
    public static int ReadAll(this IDataReader reader, Action<IDataReader> action) {
        var count = 0;
        while (reader.Read()) {
            action(reader);
            count++;
        }
        return count;
    }

  }
}